package com.aforce;
/*
 * $RCSfile: ObjLoad.java,v $
 *
 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistribution of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistribution in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * Neither the name of Sun Microsystems, Inc. or the names of
 * contributors may be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * This software is provided "AS IS," without a warranty of any
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
 * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * You acknowledge that this software is not designed, licensed or
 * intended for use in the design, construction, operation or
 * maintenance of any nuclear facility.
 *
 * $Revision: 1.4 $
 * $Date: 2007/02/09 17:21:45 $
 * $State: Exp $
 */

import com.aforce.behaviors.MouseNavigationBehavior;
import com.aforce.behaviors.EyeBehavior;
import com.aforce.behaviors.KeyboardControlBehavior;
import com.aforce.entities.Block;
import com.aforce.entities.Mine;

import com.aforce.entities.Ship;
import com.aforce.managers.EntityManager;
import com.aforce.managers.MapManager;
import com.aforce.managers.TimeManager;

import com.sun.j3d.utils.universe.*;

import javax.imageio.ImageIO;
import javax.media.j3d.*;
import javax.vecmath.*;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.LinkedList;

import com.sun.j3d.utils.geometry.Text2D;

/**
 * Simple Java 3D example program to display an .obj object.
 */
public class GraphicsEnvironment extends javax.swing.JFrame
{
	private static final long serialVersionUID = -4599738460185718361L;

	private javax.swing.JPanel drawingPanel;
	
	private SimpleUniverse univ = null;
	private BranchGroup scene = null;
	private MouseNavigationBehavior mouseListener = null;
	private EyeBehavior eyeListener = null;
	
	private Block wireBlock = new Block(0.0, 0.0, -10.0);
	
	public static LinkedList<Light> lights = new LinkedList<Light>();
	
	private EntityManager entityManager;
	

	BranchGroup fog;
	BranchGroup objScale;
	
	
	public void flipFog()
	{
		if(fog == null)
		{
			BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
			LinearFog myFog = new LinearFog( );
			myFog.setColor(new Color3f(0.05f, 0.05f, 0.2f));
			myFog.setFrontDistance( 1.0 );
			myFog.setBackDistance( 40 );
			myFog.setInfluencingBounds( bounds );
			fog = new BranchGroup();
			fog.setCapability(BranchGroup.ALLOW_DETACH);
			fog.addChild(myFog);
			objScale.addChild(fog);
		}
		else
		{
			objScale.removeChild(fog);
			fog = null;
		}
	}
	
	public BranchGroup createSceneGraph()
	{
		// Create the root of the branch graph
		BranchGroup objRoot = new BranchGroup();
		objRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);

		// Create a Transformgroup to scale all objects so they
		// appear in the scene.
		objScale = new BranchGroup();
	//	Transform3D t3d = new Transform3D();
		//t3d.setScale(0.7);
		//objScale.setTransform(t3d);
		objRoot.addChild(objScale);

		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		Background background = new Background(new Color3f(0.05f, 0.05f, 0.2f));
		background.setApplicationBounds(bounds);
		background.setApplicationBounds(bounds);
		objScale.addChild(background);
		
		// Fog

		objScale.setCapability(Group.ALLOW_CHILDREN_WRITE);
		objScale.setCapability(BranchGroup.ALLOW_DETACH);
		objScale.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
		flipFog();
		

		//try any point except 0,0,0
		Point3f txtPoint = new Point3f(1.0f,0.0f,0.0f);
		
		
		
		Text2D txt2d = new Text2D("12345", new Color3f(0.0f,0.0f,0.0f),
		  "Helvetica", 10, Font.PLAIN);

		Shape3D shape = new Shape3D(txt2d.getGeometry());
		shape.setAppearance(txt2d.getAppearance());

		txt2d = new Text2D("12345", new Color3f(1f,0.0f,0.0f),
		  "Helvetica", 50, Font.PLAIN);

		OrientedShape3D oshape = new OrientedShape3D();
		oshape.setGeometry(txt2d.getGeometry());
		oshape.setAppearance(txt2d.getAppearance());
		oshape.setAlignmentMode(OrientedShape3D.ROTATE_ABOUT_POINT);
		oshape.setRotationPoint(txtPoint);

		TransformGroup tg = new TransformGroup();
		Transform3D tf = new Transform3D();
		tf.setTranslation(new Vector3d(txtPoint));
		tg.setTransform(tf);

		tg.addChild(shape);
		tg.addChild(oshape);
		
		objScale.addChild(tg);
		
		
		objScale.addChild(wireBlock.getTransformGroup());
		objScale.addChild(new Block(0.0, 0.0, -35.0).getTransformGroup());
		objScale.addChild(new Block(0.0, 0.0, -50.0).getTransformGroup());
		
		objScale.addChild(new Mine(0.0, 0.0, -15.0).getTransformGroup());
		objScale.addChild(new Mine(0.0, 0.0, -30.0).getTransformGroup());
		

		// Generate a simple map
		for(int x = -50; x < 50; x += 10)
		{
			for(int y = -50; y < 50; y += 10)
			{
				for(int z = -50; z < 50; z += 10)
				{
					if(x != 0 || y != 0 || z != 0)
						objScale.addChild(new Block(x, y, z).getTransformGroup());
				}
			}
		}

		return objRoot;
	}

	String velocity = "unknown";
	String thrust = "unknown";
	private Canvas3D createUniverse()
	{
		// Get the preferred graphics configuration for the default screen
		GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();

		// Create a Canvas3D using the preferred configuration
		Canvas3D canvas3d = new Canvas3D(config)
		{
			private static final long serialVersionUID = 7144426579917281131L;

			public void postRender()
			{
				this.getGraphics2D().setColor(Color.white);
				this.getGraphics2D().drawString("Heads Up Display (HUD) Works!",100,100);
				
				this.getGraphics2D().setColor(Color.yellow);
				
				// Recalculate Velocity
				if(getEntityManager() != null && (int)(Math.random() * 100) % 10 == 0)
				{
					DecimalFormat df = new DecimalFormat("0.000");
					int trueVelocity = getEntityManager().getUserShip().getVelocity();
					if(trueVelocity > 0) velocity = df.format((trueVelocity/10+Math.random()))+"E3 m/s";
					if(trueVelocity == 0) velocity = "0.00 m/s";
					if(trueVelocity < 0) velocity = "-"+df.format((trueVelocity/10+Math.random()))+"E3 m/s";
				}
				
				// Recalculate Thrust
				if(getEntityManager() != null && (int)(Math.random() * 100) % 10 == 0)
				{
					DecimalFormat df = new DecimalFormat("0.000");
					int trueVelocity = getEntityManager().getUserShip().getVelocity();
					if(trueVelocity > 0) thrust = df.format((trueVelocity/10+Math.random()*3))+"E7 n";
					if(trueVelocity == 0) thrust = "0.00 n";
					if(trueVelocity < 0) thrust = "-"+df.format((trueVelocity/10+Math.random()*3))+"E7 n";
				}

				this.getGraphics2D().drawString("Current Velocity: "+velocity,425,350);
				this.getGraphics2D().drawString("Relative Thrust: "+thrust,425,365);
			//	this.getGraphics2D().drawString("Game Time: "+TimeManager.getTime(),425,380);
				
				try
				{
					BufferedImage image = ImageIO.read(new FileInputStream("data/headsup.png"));
					this.getGraphics2D().drawImage(image, (750-image.getWidth())/2, (750-image.getHeight())/2, image.getWidth(), image.getHeight(), null);
				}
				catch(FileNotFoundException e) { throw new RuntimeException(e); }
				catch(IOException e) { throw new RuntimeException(e); }
				
			/*	try
				{
					BufferedImage image = ImageIO.read(new FileInputStream("data/radar.png"));
					this.getGraphics2D().drawImage(image, (750-image.getWidth())/2, (750-image.getHeight())/2+200, image.getWidth(), image.getHeight(), null);
				}
				catch(FileNotFoundException e) { throw new RuntimeException(e); }
				catch(IOException e) { throw new RuntimeException(e); }
*/
				this.getGraphics2D().flush(false);
			}
		};

		// Create simple universe with view branch
		univ = new SimpleUniverse(canvas3d);
		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

		// add mouse behaviors to the ViewingPlatform
		ViewingPlatform viewingPlatform = univ.getViewingPlatform();

		PlatformGeometry pg = new PlatformGeometry();

		// Set up the ambient light
		Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
		AmbientLight ambientLightNode = new AmbientLight(ambientColor);
		ambientLightNode.setCapability(ambientLightNode.ALLOW_STATE_WRITE);
		lights.add(ambientLightNode);
		ambientLightNode.setInfluencingBounds(bounds);
		pg.addChild(ambientLightNode);

		// Set up the directional lights
		Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
		Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f);
		Color3f light2Color = new Color3f(1.0f, 1.0f, 1.0f);
		Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f);

		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
		light1.setCapability(ambientLightNode.ALLOW_STATE_WRITE);
		lights.add(light1);
		light1.setInfluencingBounds(bounds);
		pg.addChild(light1);

		DirectionalLight light2 = new DirectionalLight(light2Color, light2Direction);
		light2.setCapability(ambientLightNode.ALLOW_STATE_WRITE);
		lights.add(light2);
		light2.setInfluencingBounds(bounds);
		pg.addChild(light2);

		viewingPlatform.setPlatformGeometry(pg);

		BranchGroup bg = new BranchGroup();
		

		// Create the content branch and add it to the universe
		scene = createSceneGraph();
		univ.addBranchGraph(scene);

		entityManager = new EntityManager(scene);
		Ship ship = new Ship();
		entityManager.addEntity(ship);
		entityManager.setUserShip(ship);
		
		for(int i = 0; i < 20; i++)
		{
			Ship ai = new Ship();
			ai.setPosition((int)(Math.random()*1000) % MapManager.getMapSizeX(), (int)(Math.random()*1000) % MapManager.getMapSizeY(), (int)(Math.random()*1000) % MapManager.getMapSizeZ());
			ai.setVelocity(5);
			ai.enableAI();
			entityManager.addEntity(ai);
		}

		mouseListener = new MouseNavigationBehavior(canvas3d, viewingPlatform, ship);
		mouseListener.setSchedulingBounds(bounds);
		bg.addChild(mouseListener);

		KeyboardControlBehavior ol = new KeyboardControlBehavior(wireBlock, lights, ship);
		canvas3d.addKeyListener(ol);

		
		eyeListener = new EyeBehavior(viewingPlatform, ship);
		eyeListener.setSchedulingBounds(bounds);
		
		bg.addChild(eyeListener);
		
		bg.compile();

		univ.addBranchGraph(bg);

		// Ensure at least 5 msec per frame (i.e., < 200Hz)
		univ.getViewer().getView().setMinimumFrameCycleTime(30);

		return canvas3d;
	}

	/**
	 * Creates new form objectLoad2
	 */
	public GraphicsEnvironment()
	{
		// Initialize the GUI components
		initComponents();

		// Create Canvas3D and SimpleUniverse; add canvas to drawing panel
		Canvas3D c = createUniverse();
		
		drawingPanel.add(c, java.awt.BorderLayout.CENTER);

		// Set the mouse cursor
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Image image = toolkit.getImage("data/mouse.png");
		Point hotSpot = new Point(20, 20);
		Cursor cursor = toolkit.createCustomCursor(image, hotSpot, "AForce3-Cursor");
		setCursor(cursor);

		setVisible(true);
	}

	// ----------------------------------------------------------------

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	// <editor-fold defaultstate="collapsed"
	// desc=" Generated Code ">//GEN-BEGIN:initComponents
	private void initComponents()
	{
		drawingPanel = new javax.swing.JPanel();
		
		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
		setTitle("objectEye");
		drawingPanel.setLayout(new java.awt.BorderLayout());

		drawingPanel.setPreferredSize(new java.awt.Dimension(700, 700));
		getContentPane().add(drawingPanel, java.awt.BorderLayout.CENTER);

		pack();
	}
	
	public EntityManager getEntityManager()
	{
		return entityManager;
	}

}
